﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Text;

namespace Equation.Enterprise.Framework.Domain.Data
{
    public class DbRepository<T> : IRepository<T> where T:class
    {
        private readonly string _storageKey;
        private IDbSet<T> _dbSet;
        private IUnitOfWork _unitOfWork;

        public DbRepository(string storageKey)
        {
            this._storageKey = storageKey;
        }

        public DbRepository() : this (string.Empty)
        {
        }

        #region Property

        public virtual DbContext DbContext
        {
            get
            {
                if (this._storageKey == string.Empty)
                    return DbContextManager.Current;
                else
                    return DbContextManager.CurrentFor(_storageKey);
            }
        }

        public virtual IDbSet<T> DbSet
        {
            get
            {
                if (_dbSet == null)
                    _dbSet = DbContext.Set<T>();
                return _dbSet;
            }
        }

        public virtual IUnitOfWork UnitOfWork
        {
            get
            {
                if (_unitOfWork == null)
                    _unitOfWork = new UnitOfWork(this.DbContext);

                return _unitOfWork;
            }
        }

        #endregion

        #region IRepository<T> implementation

        public virtual void Add(T entity)
        {
            DbSet.Add(entity);
        }

        public virtual void Update(T entity)
        {
            DbContext.Entry(entity).State = EntityState.Modified;
        }

        public virtual void Delete(T entity)
        {
            DbSet.Remove(entity);
        }

        public virtual void Delete(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            IEnumerable<T> objects = DbSet.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                DbSet.Remove(obj);
        }

        public virtual T Get(int id)
        {
            return DbSet.Find(id);
        }

        public virtual T Get(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return DbSet.Where(where).FirstOrDefault<T>();
        }

        public virtual IEnumerable<T> List()
        {
            return DbSet.ToList();
        }

        public virtual IEnumerable<T> List(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return DbSet.Where(where).ToList();
        }

        public virtual IQueryable<T> GetQueryable()
        {
            return DbSet.AsQueryable<T>();
        }

        public virtual long Count()
        {
            return DbSet.LongCount<T>();
        }

        public virtual long Count(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return DbSet.Where(where).LongCount();
        }

        public virtual int SaveChanges()
        {
            return this.DbContext.SaveChanges();
        }

        public virtual bool IsModified(object entity)
        {
            return this.DbContext.Entry(entity).State == EntityState.Modified;
        }

        #endregion
    }
}
